local skynet = require "skynet"
local gameCmd = require "game_proto"
local tablelogic = require "tablelogic"
local Seat = require "Seat"
local GameLogic = require "GameLogic"
local Sraw = require "stable.raw"
Sraw.init()

local TableFrame = GameLogic:extend()
local MainCmdId = gameCmd.Main_ClientAndGameSvr_TableModle
local maxPlayer = 3
local MAX_DDZ_OUTCOUNT = 20
local MAX_DDZ_CARDCOUNT = 20
local Invalid_ChairId = 65535
local Invalid_Data = 255

local NtDdzOpType = 
{
    JIAODZ      =   1,  --叫地主
    NJIAODZ     =   0,  --不叫
    TI          =   11, --踢
    NTI         =   10, --不踢
    CHUAI       =   21, --踹
    NCHUAI      =   20, --不踹
    GOU         =   31, --勾
    NGOU        =   30, --不勾
    MAIZHUANG   =   41, --买庄
    NMAIZHUANG  =   40, --不买庄
    OUTCARD     =   51, --打牌
    PRESS       =   50, --过
}

--------------------------------- 通用函数 Start ------------------------
function send_data(addr,msg)
    skynet.send(addr,"lua","send_data",msg)
end

function SendDataInLua(sendAddr,subId, msg)    
    local msgSend = string.pack('>I2>I2', MainCmdId, subId)
    if msg then msgSend = msgSend..msg end
    send_data(sendAddr, msgSend)
end

function TableFrame:CalcNextUsr()
    self.currentUser = (self.currentUser+1)%maxPlayer
end

function TableFrame:BroadCastData(subId, msg)    
    local msgSend = string.pack('>I2>I2', MainCmdId, subId)
    if msg then msgSend = msgSend..msg end
    for i,v in pairs (self.chairObj) do
        if v.player.nAgentAddr ~= 0 then 
            send_data(v.player.nAgentAddr, msgSend)
        end
    end
end

function TableFrame:GetChair(player)
    for k,v in pairs(self.chairObj) do
        if player.nAgentAddr == v.player.nAgentAddr then
            return v
        end
    end

    return nil
end

function TableFrame:GetSeatCount()
    return 3,{1,2,3}
end

function TableFrame:RandCards()
    local cards  = tablelogic.cardData
    local index = 0
    local temp = 0
    for i=1, 54 do
        index = math.random(1, 54)
        temp = cards[i]
        cards[i] = cards[index]
        cards[index] = temp
    end

    return cards
end

function TableFrame:StartGameTestFaPai(allCards)
    local logicPath = skynet.getenv('gamelogic_path')
    if not logicPath then 
        return 
    end
    skynet.error('logicPath is'..logicPath)
    local fileFaPai = io.open(logicPath..'FaPai.lua',rb)
    local value = nil
    if fileFaPai then 
        value = fileFaPai:read("*a")
        fileFaPai:close() 
    else 
        skynet.error('no fapai file!!!') 
        return 
    end

    local faPaiCfg = load(value)()
    if faPaiCfg.Enable==0 then 
        return 
    end  

    --playerID
    local find = false
    for i=0, maxPlayer-1 do
        if self.chairObj[i].player.nPlayerId == faPaiCfg.PlayerID then
            find = true
        end
    end
    if find == false then 
        return
    end

    local temp = 0
    local pai = {faPaiCfg.pai_1, faPaiCfg.pai_2, faPaiCfg.pai_3}

    --手牌
    for i=1, #pai do
        for j=1, MAX_DDZ_CARDCOUNT-3 do
            for key, value in pairs(allCards) do
                if pai[i][j] == value then 
                    temp = allCards[17*(i-1)+j]
                    allCards[17*(i-1)+j] = allCards[key]
                    allCards[key] = temp
                end
            end
        end
    end

    --尾牌
    local pai_end = {faPaiCfg.pai_end}
    for i=1, #pai_end[1] do
        --skynet.error(pai_end[1][i])
    end

    for i=1, #pai_end[1] do
        for key, value in pairs(allCards) do
            if pai_end[1][i] == value then 
                temp = allCards[54-#pai_end[1]+i]
                allCards[54-#pai_end[1]+i] = allCards[key]
                allCards[key] = temp
            end
        end
    end

    return allCards
end

function TableFrame:SetTableData(Room, nMaxPlayerCount, ndiFen, nMa, nFangPaoOrZiMo, nDianPaoMaOrZiMoMa, nKeQiangGang, externData)
    self.diFen = ndiFen
    self.OneJuGameScore = ndiFen 
    self.isKanDiPai, self.isMaiZhuang, self.isTiChuaiGou = string.unpack('<I4<I4<I4', externData)

    local payCountMsg = nil
    if self.room.m_wZhiFuRen == 1 then
        payCountMsg = " 一人支付"
    else
        payCountMsg = " 房费均摊"
    end 
    local kanDiPaiMsg = nil
    if self.isKanDiPai == 1 then 
        kanDiPaiMsg = " 看底牌"
    else
        kanDiPaiMsg = " "
    end
    local maiZhuangMsg = nil
    if self.isMaiZhuang == 1 then 
        maiZhuangMsg = " 买庄"
    else
        maiZhuangMsg = " "
    end
    local tiChuaiGouMsg = nil
    if self.isTiChuaiGou == 1 then 
        tiChuaiGouMsg = " 踢踹勾"
    else
        tiChuaiGouMsg = " "
    end

    local makeRoomsg = "南通斗地主 底分【"..ndiFen.."】"..payCountMsg..kanDiPaiMsg..maiZhuangMsg..tiChuaiGouMsg

    return makeRoomsg
end
--------------------------------- 通用函数 End ----------------------------


--------------------------------- 本文件局部变量汇总 Start ---------------------------
function TableFrame:initialize(room)
    TableFrame.meta.super.initialize(self,room)
    self:TableInit()
end

function TableFrame:TableInit()
	--通用模板数据   
	self.bankerUser				=   Invalid_ChairId		--庄家
	self.currentUser			=   Invalid_ChairId		--当前用户
	self.lastOperUser			=   Invalid_ChairId		--上一个出牌用户
	self.diFen					=	Invalid_Data		--底分
	self.bei					=	Invalid_Data		--倍数
	self.OneJuGameScore			=   Invalid_Data		--每局游戏积分
	self.lastOutCardData		=   nil					--本轮最后一次出的牌数据
	self.chairObj				=   {}					--椅子
    self.thisChair              =   nil
	   
	--桌子传来的数据
    self.isKanDiPai			    =	Invalid_Data		--是否看底牌			1:是 		0:否
    self.isMaiZhuang		    =	Invalid_Data		--是否买庄 			    1:是  	    0:否
    self.isTiChuaiGou			=   Invalid_Data		--是否踢踹勾 			1:是	 	0:否
	
	--本游戏私有数据
	self.zhaDan					=	Invalid_Data		--已打出来的炸弹个数
	self.outWangZhaChair		=	Invalid_ChairId		--打出了王炸的椅子 65535代表没有人打  0,1,2 代表椅子
	self.firstOutCount			=	Invalid_Data		--地主第一手打出的牌张数，用来判断反春
	self.weiPai					=   nil					--3张尾牌
    self.gameType               =   Invalid_Data
    self.diZhu                  =   nil
    self.maiZhuangCount         =   nil
end

function TableFrame:ChairInit(chairID, player)
    self.chairObj[chairID] = {}
    self.chairObj[chairID].player = player                      --玩家
    self.chairObj[chairID].chairID = chairID                    --椅子ID

	self.chairObj[chairID].chCardData = nil						--椅子手牌
	self.chairObj[chairID].chLastOutCardData = nil				--椅子上一把出的牌
	self.chairObj[chairID].chZhaDan	= Invalid_Data				--椅子炸弹个数
	self.chairObj[chairID].chChunTian = Invalid_Data			--椅子春天状态：  0:无	1:春天	2:反春
	self.chairObj[chairID].chGameScore = Invalid_Data			--椅子积分
    self.chairObj[chairID].chIsMaiZhuang = Invalid_Data         --买庄
    self.chairObj[chairID].chOpType = Invalid_Data              --椅子的 叫踢踹勾的动作状态
	self.chairObj[chairID].chTotalJuZhaDan = 0					--椅子总炸弹
	self.chairObj[chairID].chTotalJuWangZha	= 0					--椅子总王炸
	self.chairObj[chairID].chTotalJuChunTian = 0				--椅子总春天
	self.chairObj[chairID].chTotalJuWin = 0						--椅子总胜利次数
	self.chairObj[chairID].chTotalJuDiZhu = 0					--椅子总地主次数
	self.chairObj[chairID].chTotalJuGameScore = 0				--椅子总分
end

function TableFrame:DataReset()
	--通用模板数据   
	--self.bankerUser				=   Invalid_ChairId		--庄家
	self.currentUser			=   Invalid_ChairId		--当前用户
	self.lastOperUser			=   Invalid_ChairId		--上一个出牌用户
	--self.diFen					=	Invalid_Data		--底分
	self.bei					=	self.diFen     		--倍数
	self.OneJuGameScore			=   self.diFen					--每局游戏积分
	self.lastOutCardData		=   {}					--本轮最后一次出的牌数据
	
	--本游戏私有数据
	self.zhaDan					=	0					--已打出来的炸弹个数
	self.outWangZhaChair		=	Invalid_ChairId		--打出了王炸的椅子 65535(Invalid_ChairId)代表没有人打  0,1,2 代表椅子
	self.weiPai					=   {}					--3张尾牌
    self.firstOutCount          =   0    
    self.gameType               =   Invalid_Data
    self.diZhu                  =   Invalid_ChairId
    self.maiZhuangCount         =   0

    for i=0, maxPlayer-1 do
        if self.chairObj[i]	~= nil then
            self.chairObj[i].chCardData = {}						--椅子手牌
            self.chairObj[i].chLastOutCardData	= {}				--椅子上一把出的牌
            for j=0, MAX_DDZ_OUTCOUNT-1 do
                self.chairObj[i].chLastOutCardData[j] = 0
            end

            self.chairObj[i].chZhaDan  = 0							--椅子炸弹个数   
            self.chairObj[i].chChunTian = 0						    --椅子春天状态：  0:无	1:春天	2:反春
            self.chairObj[i].chGameScore = 0						--椅子积分
            self.chairObj[i].chIsMaiZhuang = Invalid_Data           --买庄
            self.chairObj[i].chOpType = Invalid_Data                --叫踢踹勾
            --self.chTotalJuZhaDan = 0						        --椅子总炸弹
            --self.chTotalJuWangZha = 0						        --椅子总王炸
            --self.chTotalJuChunTian = 0				            --椅子总春天
            --self.chTotalJuWin = 0							        --椅子总胜利次数
            --self.chTotalJuDiZhu = 0						        --椅子总地主次数
            --self.chTotalJuGameScore = 0					        --椅子总分
        end
    end
end
--------------------------------- 本文件局部变量汇总 End -----------------------------
function TableFrame:OnSitDownSucess(seat)
    local pos = 0

    self:ChairInit(seat.m_wChairId, seat.Player)
    pos = seat.m_wChairId

    if self.bankerUser == Invalid_ChairId then
        self.bankerUser = pos
    end 

    --发送消息
    local msg = string.pack(">I2>I2<i4<i4", MainCmdId, gameCmd.Sub_GameSvrToClient_TableModle_SendTableInfo, self.room.m_nGameId, maxPlayer)
    --再告诉客户端几人麻将
    send_data(seat.Player.nAgentAddr, msg)
end

function TableFrame:OnGameMsg(scmd, smsg, Player)

    if scmd == gameCmd.Sub_ClientToGameSvr_TableModle_ntDdzMaiZhuang then

        return self:OnNetMsgMaiZhuang(smsg, Player)

    elseif scmd == gameCmd.Sub_ClientToGameSvr_TableModle_ntDdzJiaoDiZhu then
        
        return self:OnNetMsgJiaoDiZhu(smsg, Player)

    elseif scmd == gameCmd.Sub_ClientToGameSvr_TableModle_ntDdzNotJiao then

        return self:OnNetMsgNotJiao(smsg, Player)

    elseif scmd == gameCmd.Sub_ClientToGameSvr_TableModle_ntDdzTiChuaiGou then

        return self:OnNetMsgTiChuaiGou(smsg, Player)

    elseif scmd == gameCmd.Sub_ClientToGameSvr_TableModle_ntDdzOutCard then

        return self:OnNetMsgPukeOutCardReq(smsg, Player)

    elseif scmd == gameCmd.Sub_ClientToGameSvr_TableModle_ntDdzPress then

        return self:OnNetMsgPukePress(smsg, Player)

	end

end

--[[
游戏开始消息协议
struct DdzGameStartData
{
    WORD        wCurJu;                                     //局
    WORD        wBankerUser;                                //庄家用户
    WORD        wCurrentUser;                               //当前用户
    BYTE        cbCardData[MAX_DDZ_CARDCOUNT];              //我的扑克列表
    int         nGameScore[DDZ_GAME_PLAYER];                //游戏积分
    BYTE        nWeiPai[3];                                 //剩下的3张
    int         isKanDiPai;                                 //1是勾选， 0是没勾选
    int         isMaiZhuang;
    int         isTiChuaiGou;
};
]]
function TableFrame:OnEventGameStart(Table)
    self:DataReset()

    --设置庄家
	self.currentUser = self.bankerUser
    self.gameType = NtDdzOpType.MAIZHUANG
	
    --组播游戏开始
	self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_GameStart)

    --random cards
    local cards = self:RandCards()
    self:StartGameTestFaPai(cards)
	self.weiPai[0]=cards[52]
    self.weiPai[1]=cards[53]
    self.weiPai[2]=cards[54]

    --给玩家发牌
    for i=0, maxPlayer-1 do
        if self.chairObj[i] ~= nil then
            for j=0, MAX_DDZ_CARDCOUNT-3-1 do
				self.chairObj[i].chCardData[j] = cards[17*(i)+j+1]
				--[[
				if j > 5 then 
					self.chairObj[i].chCardData[j] = 0
				end
				--]]
            end
        end
    end

    --先都给尾牌赋值0
    for i=0, maxPlayer-1 do
        self.chairObj[i].chCardData[17] = 0
        self.chairObj[i].chCardData[18] = 0
        self.chairObj[i].chCardData[19] = 0
    end

	--发送信息
    for i=0, maxPlayer-1 do
        if self.chairObj[i] ~= nil then
            local dataBuf = ''
            dataBuf = dataBuf..string.pack('<I2I2I2', self.room.m_wCurJu, self.bankerUser, self.currentUser)
            for j=0, MAX_DDZ_CARDCOUNT-3-1 do
                dataBuf = dataBuf..string.pack('<B', self.chairObj[i].chCardData[j])
            end
            for j=0, maxPlayer-1 do
                dataBuf = dataBuf..string.pack('<I4', self.chairObj[i].chGameScore)
            end
			for j=0, 2 do 
				dataBuf = dataBuf..string.pack('<B', self.weiPai[j])
			end
			dataBuf = dataBuf..string.pack('<I4I4I4', self.isKanDiPai, self.isMaiZhuang, self.isTiChuaiGou)
            SendDataInLua(self.chairObj[i].player.nAgentAddr, gameCmd.Sub_GameSvrToClient_TableModle_ntDdzStart, dataBuf)
        end
    end
end

function TableFrame:OnNetMsgMaiZhuang(smsg, Player)
    local chair = self:GetChair(Player)
    local nextChairID = (chair.chairID+1)%maxPlayer
    local nextType = NtDdzOpType.MAIZHUANG
    chair.chIsMaiZhuang = string.unpack("B", smsg,  5)
    self.maiZhuangCount = self.maiZhuangCount + 1

    --若3家都买了就传叫地主
    if self.maiZhuangCount == maxPlayer then
        nextType = NtDdzOpType.JIAODZ
        self.gameType = NtDdzOpType.JIAODZ
    end

    --发送信息给客户端
    local dataBuf = string.pack('<I2BI2B', chair.chairID, chair.chIsMaiZhuang,  self.bankerUser, nextType)

    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzMaiZhuang, dataBuf)
end

--[[
服务端到客户端叫地主协议
struct DdzSrvJiaoQiangDiZhu
{
    WORD    operUsr;        //操作用户
    BYTE    operType;
    WORD    nextUsr;    
    BYTE    nextType;
    WORD    bankUsr;    
};
--]]
function TableFrame:OnNetMsgJiaoDiZhu(smsg, Player)
    local chair = self:GetChair(Player)
    local dataBuf = ''
    chair.chOpType = NtDdzOpType.JIAODZ
    self.bankerUser = chair.chairID
    self.diZhu = chair.chairID

    --叫地主了就将地主牌添加进去
    chair.chCardData[17] = self.weiPai[0]
    chair.chCardData[18] = self.weiPai[1]
    chair.chCardData[19] = self.weiPai[2]

    --不支持踢踹勾就直接接庄
    if self.isTiChuaiGou == 0 then
        dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, Invalid_ChairId, Invalid_Data, self.bankerUser)
        self.gameType = NtDdzOpType.OUTCARD
    else
        local nextChairID = (chair.chairID+1)%maxPlayer
        local nextChair = self.chairObj[nextChairID]
        --如果下家操作是不叫，上家肯定也是不叫的。那该椅子就直接接庄了
        if nextChair.chOpType == NtDdzOpType.NJIAODZ then
            dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, Invalid_ChairId, Invalid_Data, self.bankerUser)
            self.gameType = NtDdzOpType.OUTCARD
        --否则就轮到下家进行踢操作
        else
            dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, nextChairID, NtDdzOpType.TI, self.bankerUser)
            self.gameType = NtDdzOpType.TI
            self.currentUser = nextChairID
        end
    end   
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzJiaoDiZhu, dataBuf)
end

function TableFrame:OnNetMsgNotJiao(smsg, Player)
    local dataBuf = ''
    local chair = self:GetChair(Player)
    local nextChairID = (chair.chairID+1)%maxPlayer
    chair.chOpType = NtDdzOpType.NJIAODZ

    --若不是最后一个操作者 ---> 下一位玩家不是不叫就肯定不是最后一个
    if self.chairObj[nextChairID].chOpType~=NtDdzOpType.NJIAODZ then
        dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, nextChairID, NtDdzOpType.JIAODZ, Invalid_ChairId)
        self.gameType = NtDdzOpType.JIAODZ
        self.currentUser = nextChairID
    --若是最后一个操作者，那就重新发牌
    else
        local bankerUser = (self.bankerUser+1)%maxPlayer
        dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, Invalid_ChairId, Invalid_Data, Invalid_ChairId)
        self.bankerUser = bankerUser
        self.room.ResetGame()
        skynet.timeout(100, function() self.room.GameStart() end)
    end

    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzJiaoDiZhu, dataBuf)
end

function TableFrame:OnNetMsgTiChuaiGou(smsg, Player)
    local dataBuf = ''
    local chair = self:GetChair(Player)
    chair.chOpType = string.unpack("B", smsg,  5)

    --踢
    if chair.chOpType == NtDdzOpType.TI then
        local nextChairID = (chair.chairID+1)%maxPlayer
        local nextChair = self.chairObj[nextChairID]
        --我踢，下家是叫状态则上家肯定是不踢，轮下家勾
        if nextChair.chOpType == NtDdzOpType.JIAODZ then
            dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, nextChairID, NtDdzOpType.GOU, self.bankerUser)
            self.gameType = NtDdzOpType.GOU
            self.currentUser = nextChairID
        --下家是不叫，那么上家肯定是叫，那就轮到上家勾,不叫的直接略过
        elseif nextChair.chOpType == NtDdzOpType.NJIAODZ then
            local preChair = self.currentUser - 1
            if preChair == Invalid_ChairId then
                preChair = 2
            end
            dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, preChair, NtDdzOpType.GOU, self.bankerUser)
            self.gameType = NtDdzOpType.GOU
            self.currentUser = preChair
        --下家都不是肯定就是没操作过的，此时下家踹
        else
            dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, nextChairID, NtDdzOpType.CHUAI, self.bankerUser)
            self.gameType = NtDdzOpType.CHUAI
            self.currentUser = nextChairID
        end
    --不踢
    elseif chair.chOpType == NtDdzOpType.NTI then
        local nextChairID = (chair.chairID+1)%maxPlayer
        local nextChair = self.chairObj[nextChairID]
        --我不踢，下家是叫状态则上家肯定是不踢，下家不能勾，游戏开始。 
        if nextChair.chOpType == NtDdzOpType.JIAODZ then
            dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, Invalid_ChairId, Invalid_Data, self.bankerUser)
            self.gameType = NtDdzOpType.OUTCARD
        --下家是不叫，那么上家肯定是叫,不叫的直接略过。但是此时上家也不能接勾，游戏开始
        elseif nextChair.chOpType == NtDdzOpType.NJIAODZ then
            dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, Invalid_ChairId, Invalid_Data, self.bankerUser)
            self.gameType = NtDdzOpType.OUTCARD
        --都不是肯定就是没操作过的，此时踢
        else
            dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, nextChairID, NtDdzOpType.TI, self.bankerUser)
            self.gameType = NtDdzOpType.TI 
            self.currentUser = nextChairID
        end
    --踹 
    elseif chair.chOpType == NtDdzOpType.CHUAI then
        local nextChairID = (chair.chairID+1)%maxPlayer
        local nextChair = self.chairObj[nextChairID]
        --我踹，只可能是下家叫，上家踢，下家直接接勾
        dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, nextChairID, NtDdzOpType.GOU, self.bankerUser) 
        self.gameType = NtDdzOpType.GOU 
        self.currentUser = nextChairID
    --不踹
    elseif chair.chOpType == NtDdzOpType.NCHUAI then 
        local nextChairID = (chair.chairID+1)%maxPlayer
        local nextChair = self.chairObj[nextChairID]
        --不踹，下家接勾
        dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, nextChairID, NtDdzOpType.GOU, self.bankerUser) 
        self.gameType = NtDdzOpType.GOU 
        self.currentUser = nextChairID
    --勾和不勾都开始游戏
    elseif chair.chOpType==NtDdzOpType.GOU or chair.chOpType==NtDdzOpType.NGOU then 
        dataBuf = dataBuf..string.pack('<I2<B<I2<B<I2', chair.chairID, chair.chOpType, Invalid_ChairId, Invalid_Data, self.bankerUser)  
        self.gameType = NtDdzOpType.OUTCARD 
    end
  
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzTiChuaiGou, dataBuf)
end

--[[
//服务端到客户端的打牌协议
struct DdzSrvOutcard
{
    WORD            outCardUsr;                 //打牌的玩家椅子
    WORD            nextUsr;                    //下一个玩家椅子
    BYTE            cardData[MAX_DDZ_OUTCOUNT]; //打出的牌数据
    int             leftCardCount;              //打牌者剩余牌张数
};
]]
function TableFrame:OnNetMsgPukeOutCardReq(smsg, Player)
    local chair = self:GetChair(Player)
    
    --出牌解包与赋值
    local outCardData = {}
    local s = string.unpack("c20", smsg,  5)
    for i=0, MAX_DDZ_OUTCOUNT-1 do
        outCardData[i] = string.byte(s, i+1)
    end
   
    --检测出牌数据正确情况，若出的牌确实手里有则将牌删除
    self:CheckOutCardError(outCardData, chair)
  
    --检测牌型是否导致分值改变
    self:CheckScore(outCardData)

    --出牌赋值
    self.currentUser = chair.chairID
    self.lastOperUser = chair.chairID
    self.lastOutCardData = outCardData
    

    --检测是否结束
    if self:CheckIsConclue()==true then 
        return
    end

    --若还没结束，那么计算下一位用户位置，并发送给客户端
    self:CalcNextUsr()

    --发送信息给客户端
    local dataBuf = ''
    dataBuf = dataBuf..string.pack('<I2I2', chair.chairID, self.currentUser) 
    for i=0, MAX_DDZ_OUTCOUNT-1 do
        dataBuf = dataBuf..string.pack('<B', outCardData[i])
    end
    dataBuf = dataBuf..string.pack('<I4', self:GetCbCardCount(chair))
   
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzOutCard, dataBuf)

    --动作复位
    self.room.ResetWorkCount() 
end

--[[
//服务端到客户端过牌协议
struct DdzPress
{
    WORD            nextUsr;        //下一个用户
    WORD            pressUsr;       //点击过的玩家
};
]]
function TableFrame:OnNetMsgPukePress(smsg, Player)
    local chair = self:GetChair(Player)

    --没出牌就清了,否则UI会显示错误
    chair.chLastOutCardData = {}
    for i=0, MAX_DDZ_OUTCOUNT-1 do
        chair.chLastOutCardData[i] = 0
    end

    self:CalcNextUsr()
    
    local dataBuf = ''
    dataBuf = dataBuf..string.pack('<I2I2', self.currentUser, chair.chairID)
  
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzPress, dataBuf)    
end

function TableFrame:GetCbCardCount(chair)
	local count = 0
	for i=0, MAX_DDZ_OUTCOUNT-1 do
		if chair.chCardData[i] ~= 0 then 
			count = count + 1
		end
	end
	return count
end

function TableFrame:CheckIsConclue()
    if self:CheckCardOver(self.chairObj[self.currentUser])==false then
        return false
    end
    local  tempBankUser = self.currentUser
    self:GameOver()
    self.bankerUser = tempBankUser
    return true
end

function TableFrame:CheckCardOver(chair)
    for i=0, 19 do
        --skynet.error(chair.chCardData[i])
    end

    for i=0, MAX_DDZ_CARDCOUNT-1 do
        if chair.chCardData[i] ~= 0 then 
            return false  
        end
    end

    return true
end

function TableFrame:CheckChunTian()
    --春天检测
    for i=0, maxPlayer-1 do
        if i~=self.bankerUser then
            for j=0, MAX_DDZ_CARDCOUNT-3-1 do
                if self.chairObj[i].chCardData[j]==0 then
                    return 0
                end
            end
        end
    end

    self.chairObj[self.currentUser].chChunTian = 1
    self.chairObj[self.currentUser].chChunTian = self.chairObj[self.currentUser].chChunTian + 1
    self.bei = self.bei * 2
    self.OneJuGameScore = self.OneJuGameScore * 2
    --发送信息给客户端
    local dataBuf = ''
    dataBuf = dataBuf..string.pack('<i4i4', self.bei, self.zhaDan) 
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzZhaDanUpdate, dataBuf)
    return 1
end

function TableFrame:CheckFanChun()
    --反春检测
    local  nCount = 0
    for i=0, MAX_DDZ_CARDCOUNT-1 do
        if self.chairObj[self.bankerUser].chCardData[i] ~= 0 then
            nCount = nCount + 1
        end
    end

    -- 地主剩余手牌+第一手出牌不是20张，就不是反春，return
    if self.firstOutCount+nCount ~= MAX_DDZ_CARDCOUNT then
        return 0
    end

    for i=0, maxPlayer-1 do
        if i~=self.bankerUser then
            self.chairObj[i].chChunTian = 1
            self.chairObj[i].chTotalJuChunTian = self.chairObj[i].chTotalJuChunTian + 1
        end
    end

    self.bei = self.bei * 2
    self.OneJuGameScore = self.OneJuGameScore * 2
    --发送信息给客户端
    local dataBuf = ''
    dataBuf = dataBuf..string.pack('<i4i4', self.bei, self.zhaDan) 
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzZhaDanUpdate, dataBuf)
    return 1
end

--[[
//结算协议
struct DdzConclueData
{
    WORD    bankUsr;                                            //地主
    BYTE    nLeftCardCount[DDZ_GAME_PLAYER];                    //剩余牌数
    int     nZhaDanCount[DDZ_GAME_PLAYER];                      //炸弹个数
    int     gameScore[DDZ_GAME_PLAYER];                         //三个玩家游戏积分
    bool    isChunTian;                                         //1是春天   0 不是
    bool    isFanChun;                                          //1是反春  0 不是
    BYTE    isLastJu;                                           //1是最后总结算 0是中途退出
    WORD    lastOutChair;                                       //最后一手牌玩家
    BYTE    lastOutCards[MAX_DDZ_OUTCOUNT];                     //打完者最后一手牌
    BYTE    lastCbCards[DDZ_GAME_PLAYER][MAX_DDZ_CARDCOUNT];    //3家最后手牌  全是0就没有是打完牌的人  
    WORD    outWangZhaChair;                                    //65535是没有 0 1 2 代表椅子ID 
    //BYTE  tiChuaiGou[DDZ_GAME_PLAYER];                        //踢踹勾
    BYTE    maiZhuang[DDZ_GAME_PLAYER];                         //买庄
};
]]
function TableFrame:ConcludeGame()
    --春天反春检测
    local chunTian = self:CheckChunTian()
    local fanChun = self:CheckFanChun()
    local isLastJu = 0
    if self.room.m_wCurJu == self.room.m_wTotalJu then
        isLastJu = 1
    end
   
    for i=0, maxPlayer-1 do
        if i ~= self.bankerUser then
            if self.chairObj[self.bankerUser].chIsMaiZhuang == NtDdzOpType.MAIZHUANG then 	-- 地主买庄			
				if self.chairObj[i].chIsMaiZhuang == NtDdzOpType.MAIZHUANG then --农民买庄
					self.chairObj[i].chGameScore = self.chairObj[i].chGameScore + self.OneJuGameScore*3*self:ConcludeGCT(i)
                else                                                                 --农民不买庄
                    self.chairObj[i].chGameScore = self.chairObj[i].chGameScore + self.OneJuGameScore*2*self:ConcludeGCT(i)
                end
            else                                                                            -- 地主不买庄			
                if self.chairObj[i].chIsMaiZhuang == NtDdzOpType.MAIZHUANG then --农民买庄
					self.chairObj[i].chGameScore = self.chairObj[i].chGameScore + self.OneJuGameScore*2*self:ConcludeGCT(i)
                else                                                                 --农民不买庄
                    self.chairObj[i].chGameScore = self.chairObj[i].chGameScore + self.OneJuGameScore*self:ConcludeGCT(i)
                end
            end
        end
    end 
    if self.lastOperUser == self.bankerUser then
        for i=0, maxPlayer-1 do
            if i ~= self.bankerUser then
                self.chairObj[self.bankerUser].chGameScore = self.chairObj[self.bankerUser].chGameScore + self.chairObj[i].chGameScore
                self.chairObj[i].chGameScore = self.chairObj[i].chGameScore * -1 
                self.chairObj[i].chTotalJuGameScore = self.chairObj[i].chTotalJuGameScore + self.chairObj[i].chGameScore
            end
        end
        self.chairObj[self.bankerUser].chTotalJuWin = self.chairObj[self.bankerUser].chTotalJuWin + 1
    else
        for i=0, maxPlayer-1 do
            if i ~= self.bankerUser then
                self.chairObj[self.bankerUser].chGameScore = self.chairObj[self.bankerUser].chGameScore - self.chairObj[i].chGameScore
                self.chairObj[i].chTotalJuGameScore = self.chairObj[i].chTotalJuGameScore + self.chairObj[i].chGameScore
                self.chairObj[i].chTotalJuWin = self.chairObj[i].chTotalJuWin + 1
            end
            
        end
    end
    self.chairObj[self.bankerUser].chTotalJuGameScore = self.chairObj[self.bankerUser].chTotalJuGameScore + self.chairObj[self.bankerUser].chGameScore
    
    
    --发送信息给客户端
    local dataBuf = ''
	dataBuf = dataBuf..string.pack('<I2', self.diZhu)
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<B', self:GetCbCardCount(self.chairObj[i]))
    end
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chZhaDan)
    end
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chGameScore)
    end
    dataBuf = dataBuf..string.pack('<BBBI2', chunTian, fanChun, isLastJu, self.lastOperUser)
    for i=0, MAX_DDZ_OUTCOUNT-1 do
        dataBuf = dataBuf..string.pack('<B', self.lastOutCardData[i])
    end
    for i=0, maxPlayer-1 do
        for j=0, MAX_DDZ_OUTCOUNT-1 do
            dataBuf = dataBuf..string.pack('<B', self.chairObj[i].chCardData[j])
        end
    end
    dataBuf = dataBuf..string.pack('<I2', self.outWangZhaChair)
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<B', self.chairObj[i].chOpType)
    end
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<B', self.chairObj[i].chIsMaiZhuang)
    end

    skynet.error("发送结算信息！")
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzConclued, dataBuf)

    --把分设给玩家
    for i=0, maxPlayer-1 do
        self.chairObj[i].player.nScore = self.chairObj[i].chTotalJuGameScore
    end
    self.room.ConcludeGameFriend()

end

function TableFrame:ConcludeGCT(chairNum) --计算勾踹踢
    
    if self.chairObj[self.bankerUser].chOpType == NtDdzOpType.GOU then --地主选择勾
        if self.chairObj[chairNum].chOpType == NtDdzOpType.TI or self.chairObj[chairNum].chOpType == NtDdzOpType.CHUAI then --农民选择踹或者踢
            return 4
        else
            return 2
        end
    else 
        if self.chairObj[chairNum].chOpType == NtDdzOpType.TI or self.chairObj[chairNum].chOpType == NtDdzOpType.CHUAI then 
            return 2
        else
            return 1
        end
    end
    return 1

end

function TableFrame:CheckOutCardError(outCardData, chair)
    local outCardDataCout = 0
    local findCard = 0

    for i=0,19 do
        --skynet.error(outCardData[i])
    end
  
    for i=0, MAX_DDZ_OUTCOUNT-1 do
        if outCardData[i] == 0 then
            break
        end
		chair.chLastOutCardData[i] = outCardData[i]
        outCardDataCout = outCardDataCout+1
	end
       
	for i=0, outCardDataCout-1 do
		for j=0, MAX_DDZ_OUTCOUNT-1 do
			if outCardData[i] == chair.chCardData[j] then
				chair.chCardData[j] = 0
				findCard = findCard + 1
				break
			end
		end
	end

    for i=0,19 do
        --skynet.error(chair.chCardData[i])
    end

    --游戏第一手牌就是地主的第一手，为后面算反春用
    if self.firstOutCount==0 then 
        self.firstOutCount = outCardDataCout
    end

    skynet.error("findCard & outCardDataCout= ", findCard, outCardDataCout)
    if findCard == outCardDataCout then
        return true
    else
        return false
    end
end

function TableFrame:CheckScore(outCardData)
    --炸弹只可能是四张牌，多余四张直接return. 免得飞机被判断成炸弹555666带56
    if outCardData[4] ~= 0 then 
        return
    end

    if math.modf(outCardData[0]/16)==5 and math.modf(outCardData[1]/16)==5 then
        self.zhaDan = self.zhaDan+1
        self.chairObj[self.currentUser].chZhaDan = self.chairObj[self.currentUser].chZhaDan + 1
        self.chairObj[self.currentUser].chTotalJuWangZha = self.chairObj[self.currentUser].chTotalJuWangZha + 1
        self.outWangZhaChair = self.currentUser
        self.bei = self.bei * 4
        self.OneJuGameScore = self.OneJuGameScore * 4
    elseif (outCardData[0]%16==outCardData[1]%16) and (outCardData[1]%16==outCardData[2]%16) and (outCardData[2]%16==outCardData[3]%16) then
        self.zhaDan = self.zhaDan+1
        self.chairObj[self.currentUser].chZhaDan = self.chairObj[self.currentUser].chZhaDan + 1
        self.outWangZhaChair = self.currentUser
        self.bei = self.bei * 2
        self.OneJuGameScore = self.OneJuGameScore * 2
    end

    --发送信息给客户端
    local dataBuf = ''
    dataBuf = dataBuf..string.pack('<i4i4', self.bei, self.zhaDan) 
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzZhaDanUpdate, dataBuf)
end

function TableFrame:CheckCardsInOutCards(pData)
    for i=0, 23 do
        if self.jiaoPaiData == pData[i] then 
            return true
        end
    end

    return false
end

--[[
//断线重连协议
struct DdzOfflineBack
{
    int         nBei;                                           //倍数    
    int         nZhaDanCount;                                   //炸弹个数
    //int         gameType;                                       //游戏类型 1叫地主 3抢 5打牌
    WORD        wBankUser;                                      //地主ID
    WORD        outCardUsr;                                     //出牌玩家
    WORD        currer;                                        //下一个玩家
    BYTE        weiPai[3];                                      //叫牌数据
    BYTE        cbCards[MAX_DDZ_CARDCOUNT];                     //断线玩家手牌
    int         gameScore[DDZ_GAME_PLAYER];                     //三玩家游戏积分
    int         cbCardsCount[DDZ_GAME_PLAYER];                  //三家手牌的张数
    BYTE        cbCard[DDZ_GAME_PLAYER][MAX_DDZ_OUTCOUNT];      //三家打牌
}; 
]]

function TableFrame:OnPlayerOfflineBack(seat, chair)
    local  chair = self:GetChair(seat.Player)
    local dataBuf = ''
    dataBuf = dataBuf..string.pack('<i4i4i4i4i4', self.isKanDiPai, self.isMaiZhuang, self.isTiChuaiGou, self.bei, self.zhaDan)
    dataBuf = dataBuf..string.pack('<BI2I2I2', self.gameType, self.diZhu, self.lastOperUser, self.currentUser)
    for i=0, 2 do
        dataBuf = dataBuf..string.pack('<B', self.weiPai[i])
    end
    for i=0, MAX_DDZ_CARDCOUNT-1 do 
        dataBuf = dataBuf..string.pack('<B', chair.chCardData[i])
    end
    for i=0, maxPlayer-1 do 
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chGameScore)
    end
    for i=0, maxPlayer-1 do 
        dataBuf = dataBuf..string.pack('<I4', self:GetCbCardCount(self.chairObj[i]))
    end
    for i=0, maxPlayer-1 do 
        for j=0, MAX_DDZ_OUTCOUNT-1 do
            dataBuf = dataBuf..string.pack('<B', self.chairObj[i].chLastOutCardData[j])
        end
    end
    dataBuf = dataBuf..string.pack('<B', chair.chIsMaiZhuang)
    SendDataInLua(seat.Player.nAgentAddr, gameCmd.Sub_GameSvrToClient_TableModle_ntDdzOfflineBack, dataBuf)
end

function TableFrame:UserComeBack(seat)
    
end

function TableFrame:IsPlaying()
    return self.currentUser~=Invalid_ChairId 
end 
--[[
//斗地主总结算协议
struct DdzTotalConclueData
{
    int     nTotalJuZhaDan[DDZ_GAME_PLAYER];                    //总炸弹
    int     nTotalJuWangZha[DDZ_GAME_PLAYER];                   //总王炸
    int     nTotalJuChunTian[DDZ_GAME_PLAYER];                  //总春天
    int     nTotalJuWin[DDZ_GAME_PLAYER];                       //总胜利次数
    int     nTotalJuDiZhu[DDZ_GAME_PLAYER];                     //总地主次数
    int     nTotalJuGameScore[DDZ_GAME_PLAYER];                 //总分
    char    szEndTime[STR_LEN_32];                              //总时间
    BYTE    isLastJu;                                           //1是最后总结算 0是中途退出
};
]]
function TableFrame:ConcluedGameLastRound()
    local isLastJu = 0
    if self.room.m_wCurJu == self.room.m_wTotalJu then
        isLastJu = 1
    end

    local firstBuf = ''
    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_PuKeGameOver, firstBuf)

    local dataBuf = ''
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chTotalJuZhaDan)
    end
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chTotalJuWangZha)
    end
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chTotalJuChunTian)
    end
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chTotalJuWin)
    end
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chTotalJuDiZhu)
    end
    for i=0, maxPlayer-1 do
        dataBuf = dataBuf..string.pack('<i4', self.chairObj[i].chTotalJuGameScore)
    end
    dataBuf = dataBuf..string.pack('<c32',  tostring(os.date("%Y-%m-%d %H:%M:%S",os.time())) )
    dataBuf = dataBuf..string.pack('<B', isLastJu)

    self:BroadCastData(gameCmd.Sub_GameSvrToClient_TableModle_ntDdzTotalConclued, dataBuf)
end 

return TableFrame